/**
 * websocket处理封装【不能使用 WebSocket 作为类名】
 */
class WSocket
{
   /**
    * websocket 连接句柄
    * @var Websocket
    */
   ws = null
 
   /**
    * 服务器地址
    * @var
    */
   serverUrl
 
   /**
    * 心跳配置
    * @var object
    */
   heartbeat = {
     openHeartbeat: true, // 是否开启心跳
     interval: 10 * 1000, // 心跳发送间隔，默认10秒
     timer: null, // 心跳定时器
   }
 
   /**
    * 重连配置
    * @var object
    */
   reconnectConfig = {
     isReconnect: true, // 是否开启短线重连
     timer: null, // 计时器对象
     interval: 5 * 1000, // 重连间隔时间
     retry: 10, // 重连次数
   }
 
   /**
    * ws事件
    * @var Array
    */
   onEvent = []
 
   /**
    * 原生 websocket 事件
    */
   events = {
     onOpen:  e => {},
     onClose: e => {},
     onError: e => {},
   }
 
   /**
    * 构造函数
    * @param {string} url
    * @param {object} events
    */
   constructor(url, events) {
     this.serverUrl = url;
     this.events = Object.assign(this.events, events);
   }
 
   /**
    * 绑定事件
    */
   on(ev, callback) {
     this.onEvent[ev] = callback;
   }
 
   /**
    * 连接websocket
    */
   connection() {
     if (this.ws) {
       this.ws.close();
       this.ws = null;
     }
 
     this.ws = new WebSocket(this.serverUrl);
     this.ws.onopen = this.onOpen.bind(this);
     this.ws.onerror = this.onError.bind(this);
     this.ws.onmessage = this.onMessage.bind(this);
     this.ws.onclose = this.onClose.bind(this);
   }
 
   /**
    * 解析数据
    *
    * @param {Object} evt Websocket 消息
    */
   onParseData(evt) {
     return JSON.parse(evt.data);
   }
 
   /**
    * 打开连接
    *
    * @param {Object} evt Websocket 消息
    */
   onOpen(evt) {
     this.events.onOpen(evt);
     this.sendHeartbeat();
   }
 
   /**
    * 关闭连接
    *
    * @param {Object} evt Websocket 消息
    */
   onClose(evt) {
     clearInterval(this.heartbeat.timer);
     if (evt.code == 1006) {
       this.reconnect();
     }
     this.events.onClose(evt);
   }
 
   /**
    * 连接错误
    *
    * @param {Object} evt Websocket 消息
    */
   onError(evt) {
     this.events.onError(evt);
   }
 
   /**
    * 接收消息
    *
    * @param {Object} evt Websocket 消息
    */
   onMessage(evt) {
     const result = this.onParseData(evt);

     this.onEvent.hasOwnProperty(result.event) && this.onEvent[result.event](result.message, result.data);
     this.onEvent.hasOwnProperty(result.event) || console.warn(`WebSocket 消息事件[${result.event}]未绑定...`);
   }
 
   /**
    * 向服务器发送心跳数据包
    */
   sendHeartbeat() {
     if (this.heartbeat.openHeartbeat) {
       this.heartbeat.timer = setInterval(_ => {
         this.ws.send('PONG');
       }, this.heartbeat.interval);
     }
   }
 
   /**
    * 断线重连
    */
   reconnect() {
     const reconnect = this.reconnectConfig;
     if (!reconnect.isReconnect || reconnect.retry == 0) {
       return;
     }
 
     this.reconnectConfig.isReconnect = false;
 
     reconnect.timer && clearTimeout(reconnect.timer);
 
     this.reconnectConfig.timer = setTimeout(_ => {
       this.connection();
       this.reconnectConfig.isReconnect = true;
       this.reconnectConfig.retry--;
       console.log( `网络连接已断开，正在尝试重新连接(${this.reconnectConfig.retry})...`);
     }, reconnect.interval);
   }
 
   /**
    * 向服务器发送数据
    *
    * @param {Object} data
    */
   send(data) {
     this.ws && this.ws.send(JSON.stringify(data));
   }
 
   /**
    * 关闭连接
    */
   close(){
     this.ws.close();
     this.ws = null;
   }
}
 
export default WSocket;
 